#!/usr/bin/env python
#
# Copyright 2010 Lead Bulb, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""webkit main command line tool, an all in one handler for everything webdsk can do.

%(script)s <action> <application root> [options]

	%(script)s start <application dir>
		Runs application, if debug on it runs in development, if off it turns into production.
			If application is 'dsk' type:
				production: launches application with debugging off.
				development: launches application with debugging on.

			If application is 'web' type:
				production: launches web server for live use.
				development: launches web server for local use.

	%(script)s stop <application dir>
		Stops running application, killing web server daemon and engine browser (if running).

	%(script)s build <application dir>
		Only used for 'dsk' type application, will create dist executable file package

	%(script)s startproject <application dir>
		Creates a new default project template in <application dir>.
		After creation see the created settings.py and configure type.

	%(script)s commit <application dir> [--message "Changelog message"]
		If configured, commits changes to Radix Repo, does not deploy to production.
			Optionally specify a changelog message with -m option.

		If configured with to be in a local Version Control system commits
			to that (supports Subversion, Mercurial, Git). Automatically adds
			newly created files and deleted removed ones. Some version controls
			require a changelog message, specify with -m option.

	%(script)s deploy <application dir>
		Will deploy newest versions to production server, supports FTP/SFTP and Google App Engine.

		If configured for Google App Engine handles the:
			appcfg.py update <application dir>

	%(script)s --help
		Prints this help message."""

import os
import sys
import getopt
import logging

DEFAULT_ARGS = {
	'port': 8080,
	'log_level': logging.INFO,
	'login_url': '/_ah/login',
	'address': 'localhost',
}
DIR_PATH = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
SCRIPT_DIR = os.path.join(DIR_PATH, 'leadbulb', 'webdsk', 'tools')

EXTRA_PATHS = [
#	DIR_PATH,
#	os.path.join(DIR_PATH, 'new_project_template'),
	os.path.join(DIR_PATH, 'leadbulb'),
	os.path.join(DIR_PATH, 'lib'),
]

def PrintUsageExit(code):
	"""Prints usage information and exits with a status code.

	Args:
		code: Status code to pass to sys.exit() after displaying usage information.
	"""
	render_dict = DEFAULT_ARGS.copy()
	render_dict['script'] = os.path.basename(sys.argv[0])
	print sys.modules['__main__'].__doc__ % render_dict
	sys.stdout.flush()
	sys.exit(code)


def ParseArguments(argv):
	"""Parses command-line arguments.

	Args:
		argv: Command-line arguments, including the executable name, used to
			execute this application.

	Returns:
		Tuple (args, option_dict) where:
			args: List of command-line arguments following the executable name.
			option_dict: Dictionary of parsed flags that maps keys from DEFAULT_ARGS
				to their values, which are either pulled from the defaults, or from
				command-line flags.
	"""
	option_dict = DEFAULT_ARGS.copy()

	try:
		opts, args = getopt.gnu_getopt(
			argv[1:],
			'a:cdhp:',
			[ 'address=',
				'debug',
				'help',
				'port=',
				'message=',
			])
	except getopt.GetoptError, e:
		print >>sys.stderr, 'Error: %s' % e
		PrintUsageExit(1)

	for option, value in opts:
		if option in ('-h', '--help'):
			#import webdsk.tools.help
			#print sys.modules['webdsk.tools.help'].__doc__
			#sys.stdout.flush()
			#return 0
			PrintUsageExit(0)

		if option in ('-d', '--debug'):
			option_dict['log_level'] = logging.DEBUG

		if option in ('-p', '--port'):
			try:
				option_dict['port'] = int(value)
				if not (65535 > option_dict['port'] > 0):
					raise ValueError
			except ValueError:
				print >>sys.stderr, 'Invalid value supplied for port'
				PrintUsageExit(1)

		if option in ('-a', '--address'):
			option_dict['address'] = value

		if option in ('-m', '--message'):
			option_dict['message'] = message

	return args, option_dict

def fix_sys_path():
  """Fix the sys.path to include our extra paths."""
  sys.path = EXTRA_PATHS + sys.path

def SigTermHandler(signum, frame):
	"""Handler for TERM signal.

	Raises a KeyboardInterrupt to perform a graceful shutdown on SIGTERM signal.
	"""
	raise KeyboardInterrupt()

def main(argv):
	'''Parse arguments and handle actions.'''
	fix_sys_path()
	args, option_dict = ParseArguments(argv)

	if len(args) != 2:
		print >>sys.stderr, 'Invalid arguments'
		PrintUsageExit(1)

	action = args[0]

	#####
	# Handle a few actions here
	#####

	# ACTION: startproject
	if action == 'startproject' or action == 'startapp':
		from webdsk_management.startproject import startproject
		d = os.path.abspath(os.path.realpath( args[1] ))
		ret = startproject( d )
		if ret: return ret
		print 'Created new project in %s' % d
		return ret

	#####
	# Get Application Dir
	#####
	application_dir = os.path.realpath(args[1])
	option_dict['application_dir'] = application_dir
	sys.path = [application_dir] + sys.path

	# All further actions require use of Application Configuration, so import
	from conf import conf
	print 'Loaded application %s [%s]' % ( conf.get( 'application' ), conf.get( 'type' ) )

	# Parse the application type
	apptype = conf.get( 'type' )
	if apptype != 'web' and apptype != 'dsk':
		print >>sys.stderr, 'Invalid application type (must be "web" or "dsk")'
		return 1

	# ACTION: start
	if action == 'start':
		# Start web server
		from webdsk.engine.httpserver import CreateServer
		import signal

		http_server = CreateServer(
			root_path,
			port,
			serve_address=option_dict['address'])

		signal.signal(signal.SIGTERM, SigTermHandler)

		logging.info('Running application %s on port %d: http://%s:%d', config.application, port, serve_address, port)
		try:
			try:
				http_server.serve_forever()
			except KeyboardInterrupt:
				logging.info('Server interrupted by user, terminating')
			except:
				exc_info = sys.exc_info()
				info_string = '\n'.join(traceback.format_exception(*exc_info))
				logging.error('Error encountered:\n%s\nNow terminating.', info_string)
				return 1
		finally:
			http_server.server_close()

	'''
	config = None
	try:
		config = app.LoadAppConfig(root_path, {})
	except yaml_errors.EventListenerError, e:
		logging.error('Fatal error when loading application configuration:\n' + str(e))
		return 1
	except app.InvalidAppConfigError, e:
		logging.error('Application configuration file invalid:\n%s', e)
		return 1
	'''

if __name__ == '__main__':
	sys.exit(main(sys.argv))
